import React from "react";

export default class ClassComps extends React.Component {
  // 继承React.Component，也会继承四个属性：props、context、refs、updater

  box3 = React.createRef(); // 通过React.createRef()创建ref
  state = {
    x: 100,
    y: 200,
    z: 300,
  };

  changeState = () => {
    let { x, y, z } = this.state;
    /* this.setState(
      {
        x: ++x,
        y: ++y,
        z: ++z,
      },
      () => {
        console.log("state更新完毕");
      }
    ); */
   
    console.log(this.state.x); // 拿到的是更新前的值，因为setState是异步操作
    setTimeout(() => {
      this.setState({
        x: ++x,
        y: ++y,
        z: ++z,
      });
    }, 1000);
    console.log("setTimeOut:",this.state.x); 
  };

  render() {
    let { x, y, z } = this.state;
    return (
      <>
        <h2 ref="index">index</h2> {/* ref="xxx"  直接赋值*/}
        <h2 ref={(x) => (this.box2 = x)}>box2</h2>{" "}
        {/* ref={x => this.box2 = x}  函数赋值*/}
        <h2 ref={this.box3}>box3</h2>
        <DemoClass ref={(x) => (this.child1 = x)}></DemoClass>
        <DemoClass2 ref={(x) => (this.child2 = x)}></DemoClass2>
        <DemoClass3 ref={(x) => (this.child3 = x)}></DemoClass3>
        <div>
          x:{x} - y:{y} - z:{z}
        </div>
        <button onClick={this.changeState}>改变xyz</button>
      </>
    );
  }
  componentDidMount() {
    // 第一次渲染完毕 【virtual dom -> 真实dom】,此时可以获取需要操作的dom
    console.log("componentDidMount");
    console.log(this.refs.index);
    this.refs.index.style.color = "blue";
    console.log(this.box2); // <h2>box2</h2>
    console.log(this.box3.current); // {current: <h2>box3</h2>}
    console.log(this.child1); // DemoClass {props: {…}, context: {…}, refs: {…}, updater: {…}, …}
    console.log(this.child2); //报错：Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
    console.log(this.child3); // <button>子组件3按钮</button>
  }
}

/* 
  1. 受控组件：基于修改数据/状态，让视图更新，达到需要的效果 --- 推荐
  2. 非受控组件：基于ref获取dom元素，直接修改dom，达到需要的效果 --- 不推荐
 */

/**
 * 获取dom元素的三种方式：
 * 1. ref="xxx"  直接赋值  -- 不推荐使用，在React.StrictMode下会报错
 * 2. ref={x => this.box2 = x}  函数赋值
 * 3. ref={this.box3}  通过React.createRef()创建ref
 *
 * 通过ref获取class组件的实例
 */

class DemoClass extends React.Component {
  render() {
    return (
      <>
        <div>子组件1</div>
      </>
    );
  }
}

const DemoClass2 = function DemoClass2() {
  return (
    <>
      <div>子组件2</div>
    </>
  );
};

// 使用React.forwardRef()包裹函数组件，使其可以获取ref,实现ref转发
const DemoClass3 = React.forwardRef(function DemoClass3(props, ref) {
  return (
    <>
      <div>子组件3</div>
      <button ref={ref}>子组件3按钮</button>
    </>
  );
});

/**
 * 在React18中，setState操作都是异步的（不论在哪执行，例如：合成事件，周期函数，定时器....）
 * 目的：实现状态的批处理，提升性能
 * 原理：利用了更新队列【updater】机制来处理
 *    + 在当前相同的时间段内【浏览器此时可以处理的事情中】，遇到setState会立即放入到更新队列中
 *    + 此时状态/视图还未更新
 *    + 当所有的代码操作结束，会"刷新队列"，【通知更新队列中的任务执行】：把所有放入的setState合并在一起执行，只触发一次视图更新【批处理操作】
 */
